using Microsoft.EntityFrameworkCore;
using Volo.Abp.Caching;
using Volo.Abp.EntityFrameworkCore;
using WL.Think.Abp.EntityFrameworkCore;
using WL.Think.Abp.Entities;

namespace WL.Think.Abp.Repositories;

/// <summary>
/// 分类基础仓储
/// </summary>
/// <typeparam name="TCategory"></typeparam>
public abstract class BaseCachedCategoryRepository<TDbContext, TCategory> :
    EfCoreKeyRepository<TDbContext, TCategory>,
    IBaseCategoryRepository<TCategory>
    where TCategory : BaseCategory<TCategory, Guid>
    where TDbContext : AppDbContextBase<TDbContext>
{
    protected readonly IDistributedCache<List<TCategory>> Cache;

    protected BaseCachedCategoryRepository(IDbContextProvider<TDbContext> dbContextProvider, IDistributedCache<List<TCategory>> cache) : base(dbContextProvider)
    {
        Cache = cache;
    }

    public override async Task<TCategory> InsertAsync(TCategory entity, bool autoSave = false, CancellationToken cancellationToken = default)
    {
        var item = await base.InsertAsync(entity, autoSave, cancellationToken);
        ClearCache();
        return item;
    }

    public override async Task<TCategory> UpdateAsync(TCategory entity, bool autoSave = false, CancellationToken cancellationToken = default)
    {
        var item = await base.UpdateAsync(entity, autoSave, cancellationToken);
        ClearCache();
        return item;
    }

    public override async Task DeleteAsync(TCategory entity, bool autoSave = false, CancellationToken cancellationToken = default)
    {
        await base.DeleteAsync(entity, autoSave, cancellationToken);
        ClearCache();
    }

    public override async Task InsertManyAsync(IEnumerable<TCategory> entities, bool autoSave = false, CancellationToken cancellationToken = default)
    {
        await base.InsertManyAsync(entities, autoSave, cancellationToken);
        ClearCache();
    }

    public override async Task UpdateManyAsync(IEnumerable<TCategory> entities, bool autoSave = false, CancellationToken cancellationToken = default)
    {
        await base.UpdateManyAsync(entities, autoSave, cancellationToken);
        ClearCache();
    }

    public override async Task DeleteManyAsync(IEnumerable<TCategory> entities, bool autoSave = false, CancellationToken cancellationToken = default)
    {
        await base.DeleteManyAsync(entities, autoSave, cancellationToken);
        ClearCache();
    }

    public override async Task<IQueryable<TCategory>> WithDetailsAsync()
    {
        var queryable = await base.WithDetailsAsync();
        queryable = queryable.Include(s => s.Children).OrderBy(s => s.Index);
        return queryable;
    }


    public async Task<List<TCategory>> GetTreeAsync(Guid? parentId = null, CancellationToken cancellationToken = default)
    {
        var result = await Cache.GetAsync(GetTreeCacheKey(), token: cancellationToken);
        if (result == null || result.Count <= 0)
        {
            var items = await GetListAsync(x => x.IsActive, true, cancellationToken);
            if (items.Count > 0)
            {
                result = items.Where(s => s.ParentId == null).ToList();
                await Cache.SetAsync(GetTreeCacheKey(), result, token: cancellationToken);
            }
        }
        return await FilterListAsync(result ?? [], parentId, cancellationToken);
    }

    public async Task<List<TCategory>> GetActiveTreeAsync(Guid? parentId = null, CancellationToken cancellationToken = default)
    {
        var list = await Cache.GetAsync(GetActiveTreeCacheKey(), token: cancellationToken);
        if (list == null || list.Count <= 0)
        {
            var queryale = await WithDetailsAsync();
            queryale = queryale.Where(x => x.IsActive);
            list = [.. queryale];
            if (list.Count > 0)
            {
                await Cache.SetAsync(GetActiveTreeCacheKey(), list, token: cancellationToken);
            }
        }
        return await FilterListAsync(list ?? [], parentId, cancellationToken);
    }

    public async Task<int> GetMaxIndexAsync(Guid parentId)
    {
        var queryable = await GetQueryableAsync();
        return await queryable.Where(x => x.ParentId == parentId).MaxAsync(x => (int?)x.Index) ?? 0;
    }


    /// <summary>
    /// 过滤处符合条件的分类列表
    /// </summary>
    /// <param name="list"></param>
    /// <param name="parentId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    protected virtual async Task<List<TCategory>> FilterListAsync(IList<TCategory> list, Guid? parentId = null, CancellationToken cancellationToken = default)
    {
        if (list.Count == 0)
        {
            return [];
        }

        if (parentId != null)
        {
            IList<TCategory> items = [.. list.Where(s => s.Id == parentId)];
            if (items.Count <= 0)
            {
                list = [.. list.SelectMany(s => s.Children!)];
                items = await FilterListAsync(list, parentId, cancellationToken);
            }
            list = items;
        }
        else
        {
            list = [.. list.Where(s => s.ParentId == null)];
        }

        return list.ToList();
    }

    /// <summary>
    /// 清空缓存
    /// </summary>
    /// <returns></returns>
    protected virtual void ClearCache()
    {
        Task.Run(() =>
        {
            Cache.Remove(GetTreeCacheKey());
            Cache.Remove(GetActiveTreeCacheKey());
        });
    }


    /// <summary>
    /// 获取树形的缓存键
    /// </summary>
    /// <returns></returns>
    protected virtual string GetTreeCacheKey()
    {
        return $"{typeof(TCategory).Name}_Tree_ALL";
    }

    /// <summary>
    /// 获取启用树形的缓存键
    /// </summary>
    /// <returns></returns>
    protected virtual string GetActiveTreeCacheKey()
    {
        return $"{typeof(TCategory).Name}_Tree_Active";
    }
}
